/****************************************************************************************
* 文件名称: adc.c
* 
* 创建时间：2019/12/08
*
* 修改时间：2019/12/08
*
* 作    者：何鑫成
*
* 版    本：V1.0
*
* 文摘描述：ADC相关函数
*
* 说    明：
****************************************************************************************/ 
#include "adc.h"

u16 AdcValue[3] , AdcAverage[3] ;

/**
 * @brief  ADC 初始化
 * @note   规则通道模式 2个通道，连续模式 ，配合DMA使用
 **/
void ADC_Init(void)
{
    RCC -> APB2ENR |= 1 << 2 ;     //! 使能PORTA口时钟 
  
    GPIO_Init(GPIOA , 0 , GPIO_Mode_AIN) ; //! PA0 3 模拟输入
    GPIO_Init(GPIOA , 3 , GPIO_Mode_AIN) ;
    
    RCC -> APB2ENR |= 1 << 9 ;     //! ADC1时钟使能    
    RCC -> APB2RSTR |= 1 << 9 ;    //! ADC1复位
    RCC -> APB2RSTR &= ~(1<<9);    //! 复位结束      
    RCC -> CFGR &= ~(3 << 14) ;    //! 分频因子清零  
    RCC -> CFGR |= 3 << 14 ;       //! ADC 8分频
  
    ADC1 -> CR1 &= 0xF0FFFF ;      //! 工作模式清零  独立模式
    ADC1 -> CR1 &= ~(1 << 8) ;     //! 非扫描模式    
    ADC1 -> CR1 |= 1 << 8 ;        //! 扫描模式    
  
    ADC1 -> CR2 &= ~(1 << 1) ;     //! 单次转换模式
    ADC1 -> CR2 |= 1 << 1 ;        //! 连续转换模式
  
    ADC1 -> CR2 |= 1<< 8 ;         //! 启用DMA
  
    ADC1 -> CR2 &= ~(7 << 17) ;     //! 软件控制转换  SWSTART(SoftWare Start)
    ADC1 -> CR2 |= 7 << 17 ;     
  
    ADC1 -> CR2 |= 1 << 20 ;       //! 使用用外部触发(SWSTART)!!!  必须使用一个事件来触发
    ADC1 -> CR2 &= ~(1 << 11 );    //! 右对齐   
  
    ADC1 -> SQR1 &= ~(0xF<<20) ;   //! 清通道数量  
    ADC1 -> SQR1 |= 1 << 20;        //! 通道数量为2
    
    ADC1 -> SQR3 &= ~(0x1F << 0) ; //! 清规则序列1通道
    ADC1 -> SQR3 &= ~(0x1F << 5) ; //! 清规则序列2通道
    ADC1 -> SQR3 |= 0 << 0 ;       //! 通道0
    ADC1 -> SQR3 |= 3 << 5 ;       //! 通道3
  
    ADC1 -> SMPR2 |= 0x07 << 0 ;   //! 通道0 239.5周期,提高采样时间可以提高精确度   
    ADC1 -> SMPR2 |= 0x07 << 9 ;   //! 通道3 采样时间239.5
    
    ADC1 -> CR2 |= 1 << 0 ;         //! 开启AD转换器   
    ADC1 -> CR2 |= 1 << 3 ;        //! 使能复位校准  
    while(ADC1 -> CR2 & 1 << 3) ;  //! 等待校准结束   
    
    //! 该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。      
    ADC1 -> CR2 |= 1 << 2 ;        //! 开启AD校准     
    while(ADC1 -> CR2 & 1 << 2);   //! 等待校准结束
    
    ADC1 -> CR2 |= 1 << 22 ;       //! 启动规则转换通道 
}

void ADC_Init2(void)
{
    RCC -> APB2ENR |= 1 << 4 ;     //! 使能PORTC口时钟 

    GPIO_Init(GPIOC , 2 , GPIO_Mode_AIN) ; //! PC2 3 模拟输入
    GPIO_Init(GPIOC , 3 , GPIO_Mode_AIN) ;
    
    RCC -> APB2ENR |= 1 << 9 ;     //! ADC1时钟使能    
    RCC -> APB2RSTR |= 1 << 9 ;    //! ADC1复位
    RCC -> APB2RSTR &= ~(1<<9);    //! 复位结束      
    RCC -> CFGR &= ~(3 << 14) ;    //! 分频因子清零  
    RCC -> CFGR |= 3 << 14 ;       //! ADC 8分频
  
    ADC1 -> CR1 &= 0xF0FFFF ;      //! 工作模式清零  独立模式
    ADC1 -> CR1 &= ~(1 << 8) ;     //! 非扫描模式    
    ADC1 -> CR1 |= 1 << 8 ;        //! 扫描模式    
  
    ADC1 -> CR2 &= ~(1 << 1) ;     //! 单次转换模式
    ADC1 -> CR2 |= 1 << 1 ;        //! 连续转换模式
  
    ADC1 -> CR2 |= 1<< 8 ;         //! 启用DMA
  
    ADC1 -> CR2 &= ~(7 << 17) ;     //! 软件控制转换  SWSTART(SoftWare Start)
    ADC1 -> CR2 |= 7 << 17 ;     
  
    ADC1 -> CR2 |= 1 << 20 ;       //! 使用用外部触发(SWSTART)!!!  必须使用一个事件来触发
    ADC1 -> CR2 &= ~(1 << 11 );    //! 右对齐   
  
    ADC1 -> SQR1 &= ~(0xF<<20) ;   //! 清通道数量  
    ADC1 -> SQR1 |= 1 << 20;        //! 通道数量为2
    
    ADC1 -> SQR3 &= 0xFFFFFC00;    //! 规则序列1 通道ch
    ADC1 -> SQR3 |= 13 << 0 ;       //! 通道12
    ADC1 -> SQR3 |= 12 << 5 ;       //! 通道13
  
    ADC1 -> SMPR2 &= 0xFFFFFFC0 ;  //! 通道0采样时间清空    
    ADC1 -> SMPR2 |= 0x3F << 0 ;   //! 通道0 1 239.5周期,提高采样时间可以提高精确度   
  
    ADC1 -> SMPR1 &= 0X07 << 6 ;   //! 通道12 13采样时间清空  
    ADC1 -> SMPR1 &= 0X07 << 9 ; 
    ADC1 -> SMPR1 |= 0X07 << 6 ;   //! 通道12 13  239.5周期,提高采样时间可以提高精确度   
    ADC1 -> SMPR1 |= 0X07 << 9 ; 
    
    ADC1 -> CR2 |= 1 << 0 ;         //! 开启AD转换器   
    ADC1 -> CR2 |= 1 << 3 ;        //! 使能复位校准  
    while(ADC1 -> CR2 & 1 << 3) ;  //! 等待校准结束   
    
    //! 该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。      
    ADC1 -> CR2 |= 1 << 2 ;        //! 开启AD校准     
    while(ADC1 -> CR2 & 1 << 2);   //! 等待校准结束
    
    ADC1 -> CR2 |= 1 << 22 ;       //! 启动规则转换通道 
}

/**
 * @brief  ADC 注入通道初始化
 * @note   不成功
 **/
void ADC_Inject_Init(void)
{
    RCC -> APB2ENR |= 1 << 2 ;     //! 使能PORTA口时钟 
  
    GPIOA -> CRL &= 0xFFFFFF00 ;   //! PA0 1 模拟输入
    
    RCC -> APB2ENR |= 1 << 9 ;     //! ADC1时钟使能    
    RCC -> APB2RSTR |= 1 << 9 ;    //! ADC1复位
    RCC -> APB2RSTR &= ~(1<<9);    //! 复位结束      
    RCC -> CFGR &= ~(3 << 14) ;    //! 分频因子清零  
    RCC -> CFGR |= 2 << 14 ;       //! ADC 6分频
  
    ADC1 -> CR1 &= 0xF0FFFF ;      //! 工作模式清零  
    ADC1 -> CR1 |= 5 << 16 ;       //! 注入同步模式
    ADC1 -> CR1 &= ~(1 << 8) ;     //! 非扫描模式    
    ADC1 -> CR1 |= 1 << 8 ;        //! 扫描模式    
    ADC1 -> CR1 |= 1 << 10 ;       //! 自动注入通道组转换
    ADC1 -> CR2 &= ~(1 << 1) ;     //! 单次转换模式
    ADC1 -> CR2 |= 1 << 1 ;        //! 连续转换模式
  
    ADC1 -> CR2 &= ~(7 << 17) ;     //! 软件控制转换  SWSTART(SoftWare Start)
    ADC1 -> CR2 |= 7 << 17 ;     
  
    ADC1 -> CR2 |= 1 << 20 ;       //! 使用用外部触发(SWSTART)!!!  必须使用一个事件来触发
    ADC1 -> CR2 &= ~(1 << 11 ) ;   //! 右对齐   
  
    ADC1 -> JSQR &= ~(3 << 20) ;   //! 清注入通道序列长度
    ADC1 -> JSQR |= 1 << 20 ;      //! 注入通道数量为2
    
    ADC1 -> JSQR &= ~(0x3FF) ;     //! 清注入通道
    ADC1 -> JSQR |= 0x20 ;         //! 0 1 通道
  
    ADC1 -> SMPR2 &= 0xFFFFFFF8 ;  //! 通道0采样时间清空    
    ADC1 -> SMPR2 |= 0x3F << 0 ;   //! 通道0  239.5周期,提高采样时间可以提高精确度   
    
    ADC1 -> CR2 |= 1 << 0 ;         //! 开启AD转换器   
    ADC1 -> CR2 |= 1 << 3 ;        //! 使能复位校准  
    while(ADC1 -> CR2 & 1 << 3) ;  //等待校准结束   
    
    //! 该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。      
    ADC1 -> CR2 |= 1 << 2 ;        //! 开启AD校准     
    while(ADC1 -> CR2 & 1 << 2);   //! 等待校准结束
    
    ADC1 -> CR2 |= 1 << 21 ;       //! 启动规则转换通道 
}

/**
 * @brief  ADC 读取通道0的值
 **/
u16 ADC_Read_CH0_Value(void)   
{
    //! 设置转换序列         
//    ADC1 -> SQR3 &= 0xFFFFFFE0;    //! 规则序列1 通道ch
//    ADC1 -> SQR3 |= 0 ;             //! 通道0   
    ADC1 -> CR2 |= 1 << 22 ;       //! 启动规则转换通道 
    while(!(ADC1 -> SR & 1 << 1)); //! 等待转换结束        
    return ADC1->DR;               //! 返回adc值  
}
